using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace SoundManager
{

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        #region Fields

        GraphicsDeviceManager graphics;

        Grid grid;

        SpriteBatch spriteBatch;
        SpriteFont myFont;

        static Vector3 camPosition = new Vector3(0.0f, 22.0f, 22.0f);

        Matrix world = Matrix.CreateWorld(new Vector3(0.0f, 0.0f, 10.0f), new Vector3(0.0f, 0.0f, -1.0f), Vector3.Up);
        Matrix view = Matrix.CreateLookAt(camPosition, new Vector3(0.0f, 0.0f, 0.0f), Vector3.Up);
        Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 480f, 0.1f, 100f);

        protected static Random random = new Random();

        #region 3D model stuff
        private Model modelShip;
        private Texture2D[] textureShips;
        #endregion 3D model stuff

        // Sound
        static ISoundManager soundManager;
        public AudioEngine audioEngine;
        public WaveBank waveBank;
        public SoundBank soundBank;
        public AudioEmitter audioEmitter;
        public AudioListener audioListener;
        public Cue cue;

        // Input
        KeyboardState currState;
        KeyboardState lastState;

        // Actors
        private Ship[] ships = null;

        #endregion Fields

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }


        protected override void Initialize()
        {
            // Instantiate and initialize our grid
            grid = new Grid(this);
            grid.Initialize(world, view, projection);

            // Initialize the texture array
            textureShips = new Texture2D[3];

            soundManager = SoundManager.GetInstance();
            soundManager.setListenerPosition(Game1.camPosition);
            /*audioEngine = new AudioEngine("Content/sounds/sound.xgs");
            waveBank = new WaveBank(audioEngine, "Content/sounds/Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, "Content/sounds/Sound Bank.xsb");

            audioListener = new AudioListener();
            audioEmitter = new AudioEmitter();*/


            base.Initialize();
        }


        protected override void LoadContent()
        {
            // Load the 3D model
            modelShip = Content.Load<Model>("Ship");

            // Load our textures
            textureShips[0] = Content.Load<Texture2D>("ShipTexture1");

            spriteBatch = new SpriteBatch(GraphicsDevice);
            myFont = Content.Load<SpriteFont>("myFont");
        }


        protected override void UnloadContent()
        {

        }


        private void Start()
        {
            // Instantiate our 5 ships
            ships = new Ship[1];
            for (int i = 0; i < 1; ++i)
            {
                ships[i] = new Ship(this);
                Components.Add(ships[i]);
            }

            // Initialize our middle ship (the "it" ship)
            ships[0].Initialize(ref modelShip, ref textureShips, Vector3.Zero);

            // Initialize the rest of the ships
            //ships[1].Initialize(ref modelShip, ref textureShips, new Vector3(grid.LIMIT_LEFT, 0, grid.LIMIT_TOP)); // Top left
            //ships[2].Initialize(ref modelShip, ref textureShips, new Vector3(grid.LIMIT_RIGHT, 0, grid.LIMIT_TOP)); // Top right
            //ships[3].Initialize(ref modelShip, ref textureShips, new Vector3(grid.LIMIT_LEFT, 0, grid.LIMIT_BOTTOM)); // Bottom left
            //ships[4].Initialize(ref modelShip, ref textureShips, new Vector3(grid.LIMIT_RIGHT, 0, grid.LIMIT_BOTTOM)); // Bottom right

            
        }



        protected override void Update(GameTime gameTime)
        {
            soundManager.updateEngine();
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // If we're just beginning the game
            if (ships == null)
                Start();


            // Get the current keyboard state
            currState = Keyboard.GetState();

            /*audioListener.Position = new Vector3(0.0f, 22.0f, 22.0f);
            audioEmitter.Position = ships[0].getPosition();

            audioEngine.Update();*/

            // Move emitter
            if (currState.IsKeyDown(Keys.A))
                ships[0].updatePosition(new Vector3(-0.1f, 0, 0));
            if (currState.IsKeyDown(Keys.D))
                ships[0].updatePosition(new Vector3(0.1f, 0, 0));
            if (currState.IsKeyDown(Keys.W))
                ships[0].updatePosition(new Vector3(0, 0, -0.1f));
            if (currState.IsKeyDown(Keys.S))
                ships[0].updatePosition(new Vector3(0, 0, 0.1f));
            if (currState.IsKeyDown(Keys.Space) && lastState.IsKeyUp(Keys.Space))
            {
                ships[0].shoot();
                /*cue = soundBank.GetCue("shotgun_fire");
                cue.Apply3D(audioListener, audioEmitter);
                cue.Play();*/
            }
            if (currState.IsKeyDown(Keys.R) && lastState.IsKeyUp(Keys.R))
            {
                ships[0].reload();
            }

            // Check if collision between "it" ship and another ship occurs. If yes, choose new target
            //CheckTagged();

            

            // Keep all the ships within boundaries and update them
            for (int i = 0; i < 1; ++i)
            {
                // Keep within level's bounds
                if (ships[i].position.X > grid.LIMIT_RIGHT)
                    ships[i].position = new Vector3(grid.LIMIT_LEFT, 0, ships[i].position.Z);

                if (ships[i].position.X < grid.LIMIT_LEFT)
                    ships[i].position = new Vector3(grid.LIMIT_RIGHT, 0, ships[i].position.Z);

                if (ships[i].position.Z > grid.LIMIT_BOTTOM)
                    ships[i].position = new Vector3(ships[i].position.X, 0, grid.LIMIT_TOP);

                if (ships[i].position.Z < grid.LIMIT_TOP)
                    ships[i].position = new Vector3(ships[i].position.X, 0, grid.LIMIT_BOTTOM);

                ships[i].Update(gameTime);
            }

            lastState = currState;
            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.SteelBlue);

            grid.Draw(gameTime);

            for (int i = 0; i < 1; ++i)
                ships[i].Draw(gameTime, view, projection);


            // Write text in separate pass
            spriteBatch.Begin();
            spriteBatch.DrawString(myFont, "X: " + ships[0].getPosition().X, new Vector2(60, 30), Color.White);
            spriteBatch.DrawString(myFont, "Z: " + ships[0].getPosition().Z, new Vector2(60, 70), Color.White);
            spriteBatch.DrawString(myFont, "Cam X: " + Game1.camPosition.X, new Vector2(60, 110), Color.White);
            spriteBatch.DrawString(myFont, "Cam Y: " + Game1.camPosition.Y, new Vector2(60, 150), Color.White);
            spriteBatch.DrawString(myFont, "Cam Z: " + Game1.camPosition.Z, new Vector2(60, 190), Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}
